package com.yilin.tms.data.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.reflect.TypeToken;
import com.yilin.commons.exception.BusinessException;
import com.yilin.commons.util.*;
import com.yilin.tms.core.application.AppUtil;
import com.yilin.tms.core.application.PageData;

import com.yilin.tms.core.commons.utils.ParamUtil;
import com.yilin.tms.core.entity.data.etc.EtcOrder;
import com.yilin.tms.core.entity.order.goods.GoodsOrder;
import com.yilin.tms.core.entity.order.transit.TransitOrder;
import com.yilin.tms.core.entity.system.param.TruckPlate;
import com.yilin.tms.core.entity.truck.TravelLicense;
import com.yilin.tms.core.entity.truck.TruckVehicle;
import com.yilin.tms.core.entity.user.UserType;
import com.yilin.tms.core.entity.user.account.Account;
import com.yilin.tms.core.entity.user.hatch.HatchEtc;
import com.yilin.tms.core.entity.user.organize.Organize;
import com.yilin.tms.core.remote.IOrderRemote;
import com.yilin.tms.core.remote.ISystemRemote;
import com.yilin.tms.core.remote.IUserRemote;
import com.yilin.tms.core.remote.IVehicleRemote;

import com.yilin.tms.data.mapper.EtcMapper;
import com.yilin.tms.data.service.IEtcService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

@Service
@Transactional
public class EtcService extends ServiceImpl<EtcMapper, EtcOrder> implements IEtcService {

    @Resource
    IVehicleRemote vehicleRemote;
    @Resource
    IUserRemote userRemote;
    @Resource
    IOrderRemote orderRemote;
    @Resource
    EtcMapper etcMapper;
    @Resource
    ISystemRemote systemRemote;

    /**
     * 保存ETC订单
     * 发货运输时调用
     */
    @Override
    public void saveEtcOrder(TransitOrder transitOrder, Account account) {
        TruckVehicle truckVehicle = ParamUtil.isSuccess(vehicleRemote.getTruckByTruckNo(transitOrder.getTransitTruckNo()));
        if (truckVehicle.getEtcKeepStatus() == TruckVehicle.EtcKeepStatus.none) return;
        HatchEtc hatchEtc = ParamUtil.isSuccess(userRemote.getEtcHatch(account.getUserType() == UserType.platformUser ? account.getOrganizeId() : account.getSuperiorPlatId()));
        GoodsOrder goodsOrder = ParamUtil.isSuccess(orderRemote.getGoodsOrderById(transitOrder.getGoodsOrderId()));
        EtcOrder etcOrder = new EtcOrder();
        etcOrder.setEtcStatus(EtcOrder.EtcStatus.startReady);
        etcOrder.setEtcOrderType(EtcOrder.EtcOrderType.realtime);
        etcOrder.setRobOrderConfirmId(transitOrder.getId());
        etcOrder.setNum(transitOrder.getTransportNo());
        etcOrder.setPlateNumber(transitOrder.getTransitTruckNo());
        etcOrder.setPlateColor(transitOrder.getTransitTruckPlateColor());
        etcOrder.setStartTime(transitOrder.getStartTransitTime());
        etcOrder.setSourceAddr(transitOrder.getPlanningConsignorAddress());
        etcOrder.setDestAddr(transitOrder.getPlanningConsigneeAddress());
        if (goodsOrder.getDuration() != null) {
            Date date = new Date(goodsOrder.getDuration() * 1000);
            etcOrder.setPredictEndTime(DateTimeUtil.dateToString(date, "yyyy-MM-dd'T'HH:mm:ss"));
        } else {
            long msTime = transitOrder.getStartTransitTime().getTime() + 12 * 24 * 60 * 60 * 1000;//12天
            etcOrder.setPredictEndTime(DateTimeUtil.dateToString(new Date(msTime), "yyyy-MM-dd'T'HH:mm:ss"));
        }
        Integer money = MathUtil.multiplyInt(transitOrder.getDeliverTransportCost(), 100d);
        etcOrder.setFee(money);
        etcOrder.setTitleType(2);
        etcOrder.setTaxplayerCode(hatchEtc.getTaxplayerCode());
        etcOrder.setDestAddr(transitOrder.getPlanningConsigneeAddress());
        etcOrder.setEndTime(DateTimeUtil.dateToString(transitOrder.getReceiptTime(), "yyyy-MM-dd'T'HH:mm:ss"));
        etcOrder.setBillingCount(0);
        Organize organize = ParamUtil.isSuccess(userRemote.getOrganizeById(account.getOrganizeId()));
//     if (organize.getUserType() == UserType.platformUser) {
//            etcOrder.setZonePlatId(organize.getSuperiorPlatOrganizeId());
//            etcOrder.setZonePlatName(organize.getSuperiorPlatOrganizeName());
//            etcOrder.setPlatId(organize.getId());
//            etcOrder.setPlatName(organize.getOrganizeName());
//        } else if (organize.getUserType() == UserType.truckerUser || organize.getUserType() == UserType.shipperUser) {
//            Organize organizeSuper = userRemote.getOrganizeById(organize.getSuperiorPlatOrganizeId()).getData();
//            ParamUtil.isNull(organizeSuper, "获取上级平台失败");
//            etcOrder.setZonePlatId(organizeSuper.getSuperiorPlatOrganizeId());
//            etcOrder.setZonePlatName(organizeSuper.getSuperiorPlatOrganizeName());
//            etcOrder.setPlatId(organize.getSuperiorPlatOrganizeId());
//            etcOrder.setPlatName(organize.getSuperiorPlatOrganizeName());
//        }
//        saveOrUpdate(etcOrder);
    }

    /**
     * 更新ETC运单
     * 收货后调用
     */
    @Override
    public void updateEtcOrder(TransitOrder transitOrder) {
        TruckVehicle truckVehicle = ParamUtil.isSuccess(vehicleRemote.getTruckByTruckNo(transitOrder.getTransitTruckNo()));
        if (truckVehicle.getEtcKeepStatus() == TruckVehicle.EtcKeepStatus.none) return;
        EtcOrder etcOrder = getEtcOrderByTransitNo(transitOrder.getTransportNo());
        if (etcOrder == null) return;
        //如果在收货时 监测ETC未提交成功 ETC作废 标记为失效
        if (etcOrder.getEtcStatus() != EtcOrder.EtcStatus.startSuccess) {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.invalid);
            etcOrder.setFailReason("订单在收货前未开始指令，已失效，请在结束20天后重新执行");
        } else {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.endReady);
            etcOrder.setAutoPostCount(0);
        }
        etcOrder.setEndTime(DateTimeUtil.dateToString(transitOrder.getReceiptTime(), "yyyy-MM-dd'T'HH:mm:ss"));
        saveOrUpdate(etcOrder);
    }

    /**
     * AUTO POST
     * 自动实时运单指令
     */
    @Override
    public void autoWaybillStartOrEnd(Integer maxErrCount) {
        List<EtcOrder> etcOrderList = getWaitEtcOrder(maxErrCount);
//        for (EtcOrder etcOrder : etcOrderList) {
//            if (etcOrder.getEtcStatus() == EtcOrder.EtcStatus.startReady || etcOrder.getEtcStatus() == EtcOrder.EtcStatus.startFail) {
//                waybillStart(etcOrder, etcOrder.getPlatId());
//            } else if (etcOrder.getEtcStatus() == EtcOrder.EtcStatus.endReady || etcOrder.getEtcStatus() == EtcOrder.EtcStatus.endFail) {
//                waybillEnd(etcOrder, etcOrder.getPlatId());
//            }
//        }
    }

    /**
     * 自动获取下次开票时间 到达开票时间自动开票
     */
    @Override
    public void autoBillingUpdate() {
        List<EtcOrder> list = getEtcOrderListByEtcStatusByBillTime(EtcOrder.EtcStatus.endSuccess, 10);
//        for (EtcOrder etcOrder : list) {
//            etcOrder.setEtcStatus(EtcOrder.EtcStatus.billing);
//            saveOrUpdate(etcOrder);
//            resolutionEtcInvoice(etcOrder, etcOrder.getPlatId());
//        }
    }

    /**
     * 获取未查询过发票的运单编号
     */
    @Override
    public ArrayList<String> getNotQueryBillNo(Account account) {
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> retData = post(data, "FIND_NO_SEARCH_NUM", account.getOrganizeId());
        ArrayList<String> list = JsonUtil.jsonToObject((String) retData.get("msg"), new TypeToken<ArrayList<String>>() {
        });
        return list;
    }

    /**
     * 车辆自动备案
     */
    @Override
    public void autoVehicleKeep() {
        List<TruckVehicle> etcNoKeepTruck = ParamUtil.isSuccess(vehicleRemote.getEtcNoKeepTruck());
        for (TruckVehicle truck : etcNoKeepTruck) {
            TruckPlate truckPlate = ParamUtil.isSuccess(systemRemote.getTruckPlateById(truck.getCardPlateId()));
            if (!truckPlate.getCode().equals("2")) {//黄牌==2
                continue;//不支持非黄牌备案
            }
            Account account = ParamUtil.isSuccess(userRemote.getAccountById(truck.getManageUserId()));
            vehicleKeep(account.getSuperiorPlatId(), truck.getTrackNo());
        }
    }


    @Override
    public Map<String, Object> balanceQuery(Account account) {
        Map<String, Object> data = new HashMap<>();
        Map<String, Object> retData = post(data, "BALANCE_QUERY", account.getOrganizeId());
        ParamUtil.isNull(retData, "获取数据为空");
        return JsonUtil.jsonToObject(MapUtil.getMapString(retData, "msg"), new TypeToken<Map<String, Object>>() {
        });
    }

    /**
     * 解析ETC运单费用并赋值到运单
     */
    @Override
    public Map<String, Object> resolutionEtcInvoice(EtcOrder etcOrder, String platId) {
        Map<String, Object> dataMap = null;
        if (etcOrder.getEtcStatus() == EtcOrder.EtcStatus.billing) {
            dataMap = invoiceQuery(etcOrder.getNum());
        }
        if (etcOrder.getEtcStatus() == EtcOrder.EtcStatus.billingEnd) {
            if (StringUtil.isNotEmpty(etcOrder.getContext())) {
                dataMap = JsonUtil.jsonToObject(etcOrder.getContext(), new TypeToken<Map<String, Object>>() {
                });
            }
        }
        if (dataMap != null) {
            List<Object> result = (List<Object>) dataMap.get("result");
            if (result == null || result.size() == 0) {
                return dataMap;
            }
            TransitOrder transitOrder = ParamUtil.isSuccess(orderRemote.getTransitOrderByNo(etcOrder.getNum()));
            BigDecimal ectTotalFeeDecimal = new BigDecimal(0.00);
            for (Object ob : result) {
                Map<String, Object> map = (Map<String, Object>) ob;
                Double totalFee = (Double) map.get("totalAmount");
                ectTotalFeeDecimal.add(new BigDecimal(String.valueOf(totalFee)));
            }

//    TODO         orderRemote.updateOrderETCCost(transitOrder.getId(),ectTotalFeeDecimal.setScale(2,BigDecimal.ROUND_UP).toString());
        }
        return dataMap;
    }

    /**
     * 企业信息查询
     */
    @Override
    public Map<String, Object> companyQuery(Account account) {
        Map<String, Object> data = new HashMap<>();
        HatchEtc hatchEtc = ParamUtil.isSuccess(userRemote.getEtcHatch(account.getOrganizeId()));
        data.put("companyName", hatchEtc.getPlatName());
        data.put("taxplayerCode", hatchEtc.getTaxplayerCode());
        Map<String, Object> retData = post(data, "COMPANY_QUERY_V1", account.getOrganizeId());
        ParamUtil.isNull(retData, "获取数据为空");
        List<Map<String, Object>> dataMapList = JsonUtil.jsonToObject(MapUtil.getMapString(retData, "msg"), new TypeToken<List<Map<String, Object>>>() {
        });
        ParamUtil.isNull(dataMapList, "获取数据为空，请检查、数据，公司名称是否正确");
        return dataMapList.get(0);
    }

    @Override
    public PageData<EtcOrder> getEtcOrderPage(Account user, EtcOrder query, int start, Integer limit) {
        Organize organize = ParamUtil.isSuccess(userRemote.getOrganizeById(user.getOrganizeId()));
        return etcMapper.getEtcOrderPage(organize, query, new PageData<>(start, limit));
    }

    /**
     * HAND POST
     * 手动实时运单开始指令
     * +
     * 手动实时运单结束指令
     */
    @Override
    public Map<String, Object> handWaybillStartOrEnd(String etcOrderId) {
        EtcOrder etcOrder = getEtcOrderById(etcOrderId);
        if (etcOrder == null) return null;
        EtcOrder.EtcStatus[] etcStatuses = new EtcOrder.EtcStatus[]{
                EtcOrder.EtcStatus.startReady, EtcOrder.EtcStatus.startFail,
                EtcOrder.EtcStatus.endReady, EtcOrder.EtcStatus.endFail,
        };
        if (!Arrays.asList(etcStatuses).contains(etcOrder.getEtcStatus())) return null;
        ///运单
//        if (etcOrder.getEtcStatus() == EtcOrder.EtcStatus.startReady || etcOrder.getEtcStatus() == EtcOrder.EtcStatus.startFail) {
//            return waybillStart(etcOrder, etcOrder.getPlatId());
//        } else if (etcOrder.getEtcStatus() == EtcOrder.EtcStatus.endReady || etcOrder.getEtcStatus() == EtcOrder.EtcStatus.endFail) {
//            return waybillEnd(etcOrder, etcOrder.getPlatId());
//        }
        return null;
    }

    @Override
    public EtcOrder getEtcOrderById(String etcOrderId) {
        QueryWrapper<EtcOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", etcOrderId);
        return etcMapper.selectOne(queryWrapper);
    }

    @Override
    public EtcOrder getPartyEtcOrderByNum(String etcOrderNum) {
        return getOne(new QueryWrapper<EtcOrder>().eq("num", etcOrderNum));
    }

    /**
     * 运单号查询发票数据
     * TODO:付费接口
     */
    @Override
    public Map<String, Object> invoiceQuery(String confirmNo) {
//        EtcOrder etcOrder = getOne(new QueryWrapper<EtcOrder>().eq("num", confirmNo));
//        ParamUtil.isNull(etcOrder, "没有找到订单数据，不能保存开票记录，禁止开票！");
//        ParamUtil.notEquals("订单数据未在开票状态，禁止开票", etcOrder.getEtcStatus(), EtcOrder.EtcStatus.billing);
//        Map<String, Object> data = new HashMap<>();
//        data.put("num", confirmNo);//运单编号
//        Map<String, Object> retData = post(data, "WAY_BILL_NUM_FIND_INVOICE", etcOrder.getPlatId());//模板编号
//        Map<String, Object> dataMap = JsonUtil.jsonToObject((String) retData.get("msg"), new TypeToken<Map<String, Object>>() {
//        });
//        List<Object> result = (List<Object>) dataMap.get("result");
//        if (result == null || result.size() == 0) {
//            return dataMap;
//        }
//        etcOrder.setBillingCount(etcOrder.getBillingCount() + 1);
//        etcOrder.setBillingTime(new Date());
//        etcOrder.setContext((String) retData.get("msg"));
//        etcOrder.setEtcStatus(EtcOrder.EtcStatus.billingEnd);
//        saveOrUpdate(etcOrder);
        return null;
    }

    public static <T> Optional<List<T>> getList(Map<String, Object> dataMap, String key, Class<T> cls) {
        Object value = dataMap.get(key);
        if (value instanceof List) {
            List<?> list = (List<?>) value;
            List<T> result = new ArrayList<>();
            for (Object obj : list) {
                if (cls.isInstance(obj)) {
                    result.add(cls.cast(obj));
                }
            }
            return Optional.of(result);
        } else {
            return Optional.empty();
        }
    }

    /**
     * 车辆备案查询
     */
    @Override
    public Map<String, Object> vehicleKeepRecord(String platId, String plateNumber) {
        Map<String, Object> data = new HashMap<>();
        TruckVehicle truckByTrackNoT = ParamUtil.isSuccess(vehicleRemote.getTruckByTruckNo(plateNumber));
        ParamUtil.isNull(truckByTrackNoT, "获取车辆失败,未找到该车辆");
        String plateColor = "9";
        String cardPlateCode = truckByTrackNoT.getCardPlateCode();
        if (truckByTrackNoT.getCardPlateName() != null && cardPlateCode != null) {
            if (cardPlateCode.equals("1")) {
                plateColor = "0";
            } else if (cardPlateCode.equals("2")) {
                plateColor = "1";
            } else if (cardPlateCode.equals("5")) {
                plateColor = "4";
            }
        }
        data.put("waybillSource", "1");
        data.put("plateNumber", plateNumber);
        data.put("plateColor", plateColor);
        Map<String, Object> map = post(data, "VEHICLE_REGISTER_QUERY", platId);
        if (MapUtil.getMapString(map, "msg").contains("车辆未备案")) {
            TruckVehicle vehicle = vehicleRemote.getTruckByTruckNo(plateNumber).getData();
            vehicleRemote.updateVehicleStatus(vehicle.getId(), TruckVehicle.EtcKeepStatus.none);
        }
        return map;
    }


    /**
     * 车辆手动备案
     */
    @Override
    public Map<String, Object> vehicleKeep(String platId, String plateNumber) {
        Map<String, Object> dataMap;
        //查询车辆是否备案
        TruckVehicle vehicle = ParamUtil.isSuccess(vehicleRemote.getTruckByTruckNo(plateNumber));
        TravelLicense travelLicenseByVehicleId = ParamUtil.isSuccess(vehicleRemote.getTravelLicenseByVehicleId(vehicle.getId()));
        Map<String, Object> map = vehicleKeepRecord(platId, plateNumber);
        if (map.get("msg").toString().contains("车辆未备案")) {
            Map<String, Object> data = new HashMap<>();
            data.put("companyName", "贵州极舜货运有限公司");
            data.put("plateNumber", plateNumber);
            String plateColor = "9";
            if (vehicle.getCardPlateName() != null) {
                if (vehicle.getCardPlateCode() != null) {
                    switch (vehicle.getCardPlateCode()) {
                        case "1":
                            plateColor = "0";
                            String serviceOperation = "1";
                            if (travelLicenseByVehicleId != null) {//判断营运类型
                                if (travelLicenseByVehicleId.getUsageCharacteristics() != null) {
                                    if (travelLicenseByVehicleId.getUsageCharacteristics().equals("非营运")) {
                                        serviceOperation = "2";
                                    }
                                }
                            }
                            data.put("serviceOperation", serviceOperation);
                            break;
                        case "2":
                            plateColor = "1";
                            break;
                        case "5":
                            plateColor = "4";
                            break;
                    }
                }
            }
            data.put("plateColor", plateColor);
            Map<String, Object> retData = post(data, "VEHICLE_REGISTER", platId);
            dataMap = JsonUtil.jsonToObject(MapUtil.getMapString(retData, "msg"), new TypeToken<Map<String, Object>>() {
            });
            if (dataMap.get("info").toString().contains("备案失败")) {
                vehicle.setEtcKeepCount(vehicle.getEtcKeepCount() + 1);
                if (vehicle.getEtcKeepCount() > 3) {
                    vehicleRemote.updateVehicleStatus(vehicle.getId(), TruckVehicle.EtcKeepStatus.keepFill);
                } else {
                    vehicleRemote.updateVehicleStatus(vehicle.getId(), TruckVehicle.EtcKeepStatus.none);
                }
            } else if (dataMap.get("info").toString().contains("备案车辆无卡:备案失败!")) {
                dataMap.put("ret", "备案车辆无卡:备案失败!");
                vehicleRemote.updateVehicleStatus(vehicle.getId(), TruckVehicle.EtcKeepStatus.keepFill);
            } else {
                vehicleRemote.updateVehicleStatus(vehicle.getId(), TruckVehicle.EtcKeepStatus.keep);
            }
        } else {
            dataMap = new HashMap<>();
            dataMap.put("ret", "车辆已备案");
            vehicleRemote.updateVehicleStatus(vehicle.getId(), TruckVehicle.EtcKeepStatus.keep);
        }
        return dataMap;
    }

    /**
     * 月账单交易查询
     */
    @Override
    public Map<String, Object> monthlyBillQuery(Account account, String taxCode, String tradeMonth, String pageNo) {
        Map<String, Object> data = new HashMap<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH, -1);
        data.put("taxCode", taxCode == null ? "915201126884497963" : taxCode);//税号
        data.put("tradeMonth", tradeMonth == null ? calendar.get(Calendar.MONTH) : tradeMonth);//交易匹配月份
        data.put("pageNo", pageNo == null ? 1 : pageNo);//页码
        Map<String, Object> retData = post(data, "WAY_BILL_COUNT_QUERY", account.getOrganizeId());
        return JsonUtil.jsonToObject(MapUtil.getMapString(retData, "msg"), new TypeToken<Map<String, Object>>() {
        });
    }

    //获取车牌颜色编码
    @Override
    public String getPlateColor(String code) {
        switch (code) {
            case "1":
                return "0";
            case "2":
            case "91"://黄牌 + 农黄
                return "1";
            case "3":
                return "2";
            case "4":
                return "3";
            case "94":
                return "4";
            case "5":
            case "92":
            case "93"://绿色 +  农绿色 + 黄绿色
                return "5";
        }
        return "9";
    }


    /**
     * 保存并全自动开始并结束历史ETC订单
     */
    @Override
    public void saveHistoryEtcOrder(EtcOrder etcOrder, Account account) {
        if (!etcOrder.getStartTime().toString().contains("T")) {
            etcOrder.setStartTime(etcOrder.getStartTime());
            long msTime = etcOrder.getStartTime().getTime() + 10 * 24 * 60 * 60 * 1000;//10天
            etcOrder.setPredictEndTime(DateTimeUtil.dateToString(new Date(msTime), "yyyy-MM-dd'T'HH:mm:ss"));
        } else {
            long msTime = etcOrder.getStartTime().getTime() + 10 * 24 * 60 * 60 * 1000;//10天
            etcOrder.setPredictEndTime(DateTimeUtil.dateToString(new Date(msTime), "yyyy-MM-dd'T'HH:mm:ss"));
        }
        if (etcOrder.getEndTime() == null) {
            throw new BusinessException("运单结束时间为空，请先完成运单或修复时间数据！");
        }
        if (!etcOrder.getEndTime().contains("T")) {
            Date date = DateTimeUtil.stringToDate(etcOrder.getEndTime(), null);
            etcOrder.setEndTime(DateTimeUtil.dateToString(date, "yyyy-MM-dd'T'HH:mm:ss"));
        }
        if (etcOrder.getPlateColor() == null) {
            TruckVehicle truckVehicle = vehicleRemote.getTruckByTruckNo(etcOrder.getPlateNumber()).getData();
            if (truckVehicle == null) {
                throw new BusinessException("运单车辆未在平台注册！");
            }
            etcOrder.setPlateColor(getPlateColor(truckVehicle.getCardPlateCode()));
        }
        etcOrder.setTitleType(2);
        etcOrder.setTaxplayerCode("915201126884497963");
        etcOrder.setEtcOrderType(EtcOrder.EtcOrderType.history);
        etcOrder.setBillingCount(0);
        etcOrder.setRealDestAddr(etcOrder.getDestAddr());

        if (etcOrder.getId() == null) {
            saveOrUpdate(etcOrder);
        }
        //历史运单开始指令
        historyWaybillStart(etcOrder, account);
        //历史运单结束指令
        if (etcOrder.getEtcStatus() != EtcOrder.EtcStatus.startSuccess) {
            throw new BusinessException("开始提交指令失败:" + etcOrder.getFailReason());
        }
        historyWaybillEnd(etcOrder, account);
        if (etcOrder.getEtcStatus() != EtcOrder.EtcStatus.endSuccess) {
            throw new BusinessException("结束提交指令失败:" + etcOrder.getFailReason());
        }
        etcOrder.setEtcStatus(EtcOrder.EtcStatus.billing);
        etcOrder.setNextBillingTime(new Date());//下一次开票时间
        saveOrUpdate(etcOrder);
    }


    //开始运单
    private Map<String, Object> waybillStart(EtcOrder etcOrder, String platId) {
        //计算预计完成时间
        Map<String, Object> data = new HashMap<>();
        data.put("num", etcOrder.getNum());//运单编号
        data.put("plateNumber", etcOrder.getPlateNumber());//车牌号
        data.put("plateColor", etcOrder.getPlateColor());//车牌颜色
        data.put("startTime", etcOrder.getStartTime());//运单开始时间(合同确认时间)
        data.put("sourceAddr", etcOrder.getSourceAddr());//运单开始地址
        data.put("destAddr", etcOrder.getDestAddr());//运单目的地址
        data.put("predictEndTime", etcOrder.getPredictEndTime());//运单预计完成时间
        data.put("fee", etcOrder.getFee());//运单费用 分
        data.put("titleType", etcOrder.getTitleType());//发票抬头类型1-2
        data.put("taxplayerCode", etcOrder.getTaxplayerCode());//
        Map<String, Object> retData = post(data, "WAY_BILL_START", platId);
        Map<String, Object> dataMap = JsonUtil.jsonToObject((String) retData.get("msg"), new TypeToken<Map<String, Object>>() {
        });
        if (dataMap.get("info").equals("开始指令已经上传成功")) {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.startSuccess);
        } else {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.startFail);
            if (etcOrder.getBillingCount() == null) etcOrder.setAutoPostCount(0);
            etcOrder.setAutoPostCount(etcOrder.getBillingCount() + 1);
            etcOrder.setFailReason(dataMap.get("info").toString());
        }
        saveOrUpdate(etcOrder);
        return dataMap;
    }

    //结束运单
    private Map<String, Object> waybillEnd(EtcOrder etcOrder, String platId) {
        //未提交的运单
        Map<String, Object> data = new HashMap<>();
        data.put("num", etcOrder.getNum());//运单编号
        data.put("realDestAddr", etcOrder.getRealDestAddr());//运单实际目的地址
        data.put("endTime", etcOrder.getEndTime());//运单实际结束时间
        Map<String, Object> retData = post(data, "WAY_BILL_END", platId);
        Map<String, Object> dataMap = JsonUtil.jsonToObject((String) retData.get("msg"), new TypeToken<Map<String, Object>>() {
        });
        if (dataMap.get("info").equals("成功")) {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.endSuccess);
            Date nextDate = DateTimeUtil.stringToDate(etcOrder.getEndTime(), null);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(nextDate == null ? new Date() : nextDate);
            calendar.add(Calendar.DATE, +1);
            etcOrder.setNextBillingTime(calendar.getTime());//下一次开票时间
        } else {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.endFail);
            if (etcOrder.getBillingCount() == null) etcOrder.setAutoPostCount(0);
            etcOrder.setAutoPostCount(etcOrder.getBillingCount() + 1);
            etcOrder.setFailReason(dataMap.get("info").toString());
        }
        saveOrUpdate(etcOrder);
        return dataMap;
    }


    /**
     * 历史运单开始指令 20天以前的运单才可以上传
     */
    private void historyWaybillStart(EtcOrder etcOrder, Account account) {
        Map<String, Object> data = new HashMap<>();
        data.put("num", etcOrder.getNum());//运单编号
        data.put("plateNumber", etcOrder.getPlateNumber());//车牌号
        data.put("plateColor", etcOrder.getPlateColor());//车牌颜色
        data.put("startTime", etcOrder.getStartTime());//运单开始时间
        data.put("sourceAddr", etcOrder.getSourceAddr());//运单开始地址
        data.put("destAddr", etcOrder.getDestAddr());//运单目的地址
        data.put("predictEndTime", etcOrder.getPredictEndTime());//运单预计完成时间appSecret
        data.put("fee", etcOrder.getFee());//运单费用
        data.put("titleType", etcOrder.getTitleType());//发票抬头类型1-2
        data.put("taxplayerCode", etcOrder.getTaxplayerCode());//
        Map<String, Object> retData = post(data, "WAY_BILL_HISTORY_START", account.getOrganizeId());
        Map<String, Object> dataMap = JsonUtil.jsonToObject((String) retData.get("msg"), new TypeToken<Map<String, Object>>() {
        });
        if (dataMap.get("info").equals("成功")) {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.startSuccess);
        } else {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.startFail);
            etcOrder.setFailReason((String) dataMap.get("info"));
        }
    }

    /**
     * 历史运单结束指令 20天以前的运单才可以上传
     */
    private void historyWaybillEnd(EtcOrder etcOrder, Account account) {
        Map<String, Object> data = new HashMap<>();
        data.put("num", etcOrder.getNum());//运单编号
        data.put("realDestAddr", etcOrder.getRealDestAddr());//运单实际目的地址
        data.put("endTime", etcOrder.getEndTime());//运单实际结束时间
        Map<String, Object> retData = post(data, "WAY_BILL_HISTORY_END", account.getOrganizeId());
        Map<String, Object> dataMap = JsonUtil.jsonToObject((String) retData.get("msg"), new TypeToken<Map<String, Object>>() {
        });
        if (dataMap.get("info").equals("成功")) {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.endSuccess);
        } else {
            etcOrder.setEtcStatus(EtcOrder.EtcStatus.endFail);
            etcOrder.setFailReason((String) dataMap.get("info"));
        }
    }

    @Override
    public EtcOrder getEtcOrderByTransitNo(String transitNo) {
        QueryWrapper<EtcOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("num", transitNo);
        queryWrapper.eq("is_deleted", 0);
        return etcMapper.selectOne(queryWrapper);
    }

    /**
     * 实时运单提交 失败3次需手动提交
     */
    @Override
    public List<EtcOrder> getWaitEtcOrder(Integer maxErrCount) {
        QueryWrapper<EtcOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.le("auto_post_count", maxErrCount == null ? 3 : maxErrCount);
        Object[] nums = {EtcOrder.EtcStatus.startReady.index, EtcOrder.EtcStatus.startFail.index, EtcOrder.EtcStatus.endReady.index, EtcOrder.EtcStatus.endFail.index};
        queryWrapper.in("etc_status", nums);
        queryWrapper.ne("is_deleted", 0);
        return etcMapper.selectList(queryWrapper);
    }

    /**
     * 自动获取下次开票时间 到达开票时间自动开票
     */
    @Override
    public List<EtcOrder> getEtcOrderListByEtcStatusByBillTime(EtcOrder.EtcStatus etcStatus, int count) {
        QueryWrapper<EtcOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("next_billing_time", new Date());
        Object[] nums = {EtcOrder.EtcStatus.startReady.index, EtcOrder.EtcStatus.startFail.index, EtcOrder.EtcStatus.endReady.index, EtcOrder.EtcStatus.endFail.index};
        queryWrapper.ne("etc_status", etcStatus.index);
        queryWrapper.ne("is_deleted", 0);
        return etcMapper.selectList(queryWrapper);
    }


    //公共请求
    private Map<String, Object> post(Map<String, Object> data, String api, String platId) {
        HatchEtc hatchEtc = ParamUtil.isSuccess(userRemote.getEtcHatch(platId));

        ParamUtil.isNull(hatchEtc, "获取ETC配置失败");
        Map<String, Object> map = new HashMap<>();
        map.put("api", api);
        map.put("appKey", hatchEtc.getAppKey());
        map.put("data", getSignData(data, hatchEtc.getTaxplayerCode()));
        map.put("appSecret", hatchEtc.getAppSecret());
        String returnData = null;
        try {
            String json = JsonUtil.objectToJson(map);
            returnData = HttpService.httpPostWithJson(hatchEtc.getUrl(), json);
        } catch (Exception e) {
            throw new BusinessException("ETC请求失败，请重试！");
        }
        if (returnData == null) {
            return null;
        }
        Map<String, Object> mapMap = JsonUtil.jsonToObject(returnData, new TypeToken<Map<String, Object>>() {
        });
        //接口请求成功
        if (!MapUtil.getMapString(mapMap, "code").equals("200")) {
            throw new BusinessException("ETC请求失败，返回：" + mapMap.get("msg"));
        }
        //请求出错
        if (!MapUtil.getMapString(mapMap, "data").equals("1")) {
            mapMap.put("msg", "{info:\"" + mapMap.get("msg") + "\"}");
        }
        return mapMap;
    }

    /*  公共方法：签名*/
    //md5(appSecret以&拼接业务参数)32大写【业务参数：JSON转map，然后按key升序以&拼接】
    private Map<String, Object> getSignData(Map<String, Object> data, String taxplayerCode) {
        //业务参数排序
        Map<String, Object> map = ArrayUtil.sortByKey(data);
        //以&拼接业务参数
        String signVarStr = getSignVarStr(map);
        String signStr = AppUtil.md5(taxplayerCode + "&" + signVarStr);
        //32大写
        signStr = signStr.toUpperCase().substring(0, 32);
        data.put("sign", signStr);
        return data;
    }

    /* /以&拼接业务参数*/
    private String getSignVarStr(Map<String, Object> map) {
        StringBuilder varString = new StringBuilder();
        for (String key : map.keySet()) {
            varString.append(key).append("=").append(map.get(key)).append("&");
        }
        if (varString.length() > 0) {
            return varString.substring(0, varString.toString().length() - 1);
        } else {
            return varString.toString();
        }
    }

}
